aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pages/og/[slug].png.ts
blob: 52b790bf530c66b25108d69de59675e649512b88 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import satori from "satori";
import { Resvg } from "@resvg/resvg-js";
import { readFileSync } from "node:fs";

const pages: Record<string, string> = {
  index: "だれもがしあわせに暮らせるまちへ",
  jisseki: "実績",
  policy: "私の方針",
  support: "ご支援",
  contact: "コンタクト",
  "whisper-to-ai-moji-okoshi":
    "無料・超高精度のWhisper + 生成AIで文字起こしする方法",
  "koubunsyo-kanri": "公文書管理の不正追及の軌跡",
  "ijime-judai-jitai": "いじめ重大事態への対応の軌跡",
  "fukushi-shisetsu-gyakutai": "障害者福祉施設における虐待通報対応の軌跡",
  "aiki-kouen": "合気公園の軌跡",
  "joutyo-koteikyu": "情緒固定級の軌跡",
  "kajo-seigen-kanwa": "過剰な制限緩和の軌跡",
  "saresio-kaihatu": "東京サレジオ学園北側開発問題の軌跡",
  "vaccine-kyuusai-tekiseika": "ワクチン副反応救済制度の適正化の軌跡",
  "dislexia-taiou": "ディスレクシア(読み書き障害)対応の軌跡",
  "ippan-situmon": "一般質問",
};

export async function getStaticPaths() {
  return Object.keys(pages).map((slug) => ({ params: { slug } }));
}

const fontBuffer = readFileSync("node_modules/.noto-sans-jp.otf");
const faceiconBuffer = readFileSync("public/img/faceicon.jpg");
const faceiconBase64 = `data:image/jpeg;base64,${faceiconBuffer.toString("base64")}`;

export async function GET({ params }: { params: { slug: string } }) {
  const slug = params.slug;
  const title = pages[slug] ?? "小平市議 安竹洋平 公式サイト";

  const svg = await satori(
    {
      type: "div",
      props: {
        style: {
          display: "flex",
          width: "1200px",
          height: "630px",
          background: "linear-gradient(135deg, #3730a3 0%, #4f46e5 100%)",
          color: "#ffffff",
          fontFamily: "sans-serif",
          padding: "60px 80px",
          alignItems: "center",
          gap: "48px",
        },
        children: [
          {
            type: "img",
            props: {
              src: faceiconBase64,
              width: 200,
              height: 200,
              style: {
                borderRadius: "50%",
                border: "4px solid rgba(255,255,255,0.3)",
                flexShrink: "0",
              },
            },
          },
          {
            type: "div",
            props: {
              style: { display: "flex", flexDirection: "column", gap: "16px", flex: "1" },
              children: [
                {
                  type: "div",
                  props: {
                    style: { fontSize: "48px", fontWeight: "700", lineHeight: "1.3", letterSpacing: "-0.02em" },
                    children: title,
                  },
                },
                {
                  type: "div",
                  props: {
                    style: { fontSize: "28px", fontWeight: "500", opacity: "0.8", color: "#e0e7ff" },
                    children: "小平市議 安竹洋平",
                  },
                },
                {
                  type: "div",
                  props: {
                    style: { fontSize: "20px", fontWeight: "400", opacity: "0.5", color: "#e0e7ff", marginTop: "8px" },
                    children: "yasutakeyohei.com",
                  },
                },
              ],
            },
          },
        ],
      },
    } as any,
    {
      width: 1200,
      height: 630,
      fonts: [{ name: "sans-serif", data: fontBuffer, weight: 400, style: "normal" }],
    }
  );

  const resvg = new Resvg(svg, { fitTo: { mode: "width", value: 1200 } });
  const pngBuffer = resvg.render().asPng();

  return new Response(pngBuffer, {
    headers: {
      "Content-Type": "image/png",
      "Cache-Control": "public, max-age=31536000, immutable",
    },
  });
}